package tako.wisers.com.android.apis.parser;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.htmlparser.Node;
import org.htmlparser.NodeFilter;
import org.htmlparser.Parser;
import org.htmlparser.filters.NodeClassFilter;
import org.htmlparser.filters.OrFilter;
import org.htmlparser.tags.Div;
import org.htmlparser.tags.HeadingTag;
import org.htmlparser.tags.ImageTag;
import org.htmlparser.tags.LinkTag;
import org.htmlparser.tags.Span;
import org.htmlparser.util.NodeList;
import org.htmlparser.util.ParserException;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;

import tako.wisers.com.android.apis.adapter.BitmapUtils;
import tako.wisers.com.android.apis.http.HttpGeter;
import tako.wisers.com.android.apis.item.NewsItem;
import tako.wisers.com.android.apis.util.Base64Coder;

@SuppressWarnings("unchecked")
public class NewsHeadlineParser {
	public final String srcURL = "http://news.google.com/news/search?pz=1&cf=all&ned={0}&hl=zh-TW&q={1}&um=1&ie=UTF-8&sa=N&tab=wn";
	public final Pattern charPatten = Pattern.compile("&#?[a-z0-9]+;");
	private final int TITLE_NODE = 1;
	private final int SUB_TITLE_NODE = 2;
	private final int BODY_NODE = 3;
	private final int IMAGE_NODE = 4;
	public static final String TILTE_TAG = "title";
	public static final String INTENT_TAG = "intent";
	public static final String PUBLICHER_TAG = "source";
	public static final String DATE_TAG = "date ";
	public static final String SNIPPET_TAG = "snippet";

	public List<NewsItem> getNewsHeadlines(String keyword, String countryCode) {
		List<NewsItem> HeadlineList = null;
		
		try {
			String urlStr = "http://news.google.com";
			if (keyword != null) {
				urlStr = srcURL.replace("{1}", URLEncoder.encode(keyword,
						"UTF-8"));
				if (countryCode != null) {
					urlStr = urlStr.replace("{0}", countryCode);
				} else {
					urlStr = urlStr.replace("{0}", "HK");
				}
			}
			HttpGeter geter = new HttpGeter(urlStr);
			String html = geter.getContent();
			HeadlineList = parserHtml(html);
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
		}
		return HeadlineList;
	}

	private List<NewsItem> parserHtml(String html) {
		Map<Node, NewsItem> result = new HashMap<Node, NewsItem>();
		Parser parser = Parser.createParser(html, "UTF-8");
		NodeFilter textFilter = new NodeClassFilter(HeadingTag.class);
		NodeFilter linkFilter = new NodeClassFilter(LinkTag.class);
		NodeFilter divFilter = new NodeClassFilter(Div.class);
		NodeFilter spanFilter = new NodeClassFilter(Span.class);
		NodeFilter imgFilter = new NodeClassFilter(ImageTag.class);
		OrFilter lastFilter = new OrFilter();
		lastFilter.setPredicates(new NodeFilter[] { textFilter, linkFilter,
				divFilter, spanFilter, imgFilter });
		try {
			NodeList nodes = parser.parse(lastFilter);
			parserNodeList(nodes, result);
		} catch (ParserException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return new ArrayList<NewsItem>(result.values());
	}

	private void parserNodeList(NodeList nodes, Map<Node, NewsItem> results) {
		for (int i = 0; i < nodes.size(); i++) {
			Node node = nodes.elementAt(i);
			switch (featureParser(node)) {
			case TITLE_NODE:
				parserLinkTag(node, results);
				break;
			case IMAGE_NODE:
				parserImageTag(node, results);
				break;
			case SUB_TITLE_NODE:
			case BODY_NODE:
				parserSpanTag(node, results);
			}

		}
	}

	private void parserImageTag(Node perentNode, Map<Node, NewsItem> results){
		String imageURL =  getImage(perentNode,results);
		Node root = perentNode.getParent();
		NewsItem item = getPanoramioItem(results, root);
		Bitmap image = BitmapUtils.loadBitmap(imageURL);
		item.setBitmap(image); 
		item.setPhotoUrl(imageURL);
		results.put(root, item);
	}

	private String getImage(Node perentNode, Map<Node, NewsItem> results) {
		if(perentNode == null) return null;
		Node[] nodes = perentNode.getChildren().toNodeArray();
		for (Node node : nodes) {
			if (node instanceof ImageTag) {
				ImageTag imgTag = (ImageTag) node;
				return imgTag.getImageURL();
			}else {
				return getImage(node, results);
			}
		}
		return null;
	}

	private void parserSpanTag(Node perentNode, Map<Node, NewsItem> results) {
		List<Span> tagList = getSpanTag(results, perentNode);
		if (tagList == null)
			return;
		Node root = perentNode.getParent();
		NewsItem item = getPanoramioItem(results, root);
		for (Span span : tagList) {
			String feature = span.getAttribute("class");
			if (feature.equals(PUBLICHER_TAG)) {
				String Owner = decode(span.getStringText());
				if (Owner == null || Owner.equals(""))
					Owner = "Google News";
				item.setOwner(Owner);
			} else if (feature.equals(DATE_TAG)) {
				item.setDate(decode(span.getStringText()));
			}
			results.put(root, item);
		}

	}

	private String decode(String str) {
		Pattern pattern = Pattern.compile("&#[0-9]+;");
		str = str.replaceAll("&#lrm;", "");
		if (pattern.matcher(str).find()) {
			String[] codes = str.split(";");
			String result = "";
			for (String code : codes) {
				if (code.contains("&#")) {
					int index = code.indexOf("&#");
					result += code.substring(0, index);
					char charCode = (char) new Integer(code
							.substring(index + 2)).intValue();
					result += charCode;
				}
			}
			return result;
		}
		return str;
	}

	private List<Span> getSpanTag(Map<Node, NewsItem> results, Node perentNode) {
		List<Span> tagList = new ArrayList<Span>();
		for (Node node : perentNode.getChildren().toNodeArray()) {
			if (node instanceof Span) {
				Span span = (Span) node;
				String feature = span.getAttribute("class").replace("\\s+", "");
				if (feature != null
						&& (feature.equalsIgnoreCase(PUBLICHER_TAG) || feature
								.equalsIgnoreCase(DATE_TAG))) {
					tagList.add(span);
				}
			} else if (node instanceof Div) {
				Div div = (Div) node;
				String feature = div.getAttribute("class").replace("\\s+", "");
				if (feature != null && feature.equalsIgnoreCase(SNIPPET_TAG)) {
					NewsItem item = getPanoramioItem(results, perentNode
							.getParent());
					String content = div.getChildrenHTML();
					item.setContent(content);
					results.put(perentNode.getParent(), item);
					return null;
				}
			}
		}
		return tagList;
	}

	private void parserLinkTag(Node perentNode, Map<Node, NewsItem> results) {
		LinkTag linkNode = getLinkTag(perentNode.getFirstChild());
		if (linkNode == null)
			return;
		String title = linkNode.getLinkText();
		Node root = perentNode.getParent();
		NewsItem item = getPanoramioItem(results, root);
		Matcher matcher = charPatten.matcher(title);
		title = matcher.replaceAll(" ");
		item.setTitle(title);
		item.setURL(linkNode.getLink());
		results.put(root, item);
	}

	private NewsItem getPanoramioItem(Map<Node, NewsItem> results, Node root) {
		NewsItem map;
		if (results.containsKey(root)) {
			map = results.get(root);
		} else {
			map = new NewsItem();
		}
		return map;
	}

	private LinkTag getLinkTag(Node node) {
		LinkTag temp = null;
		if (node == null)
			return temp;
		if (node instanceof LinkTag) {
			temp = (LinkTag) node;
		} else {
			temp = getLinkTag(node.getNextSibling());
		}
		return temp;
	}

	private int featureParser(Node node) {
		if (node instanceof HeadingTag) {
			HeadingTag head = (HeadingTag) node;
			String feature = head.getAttribute("class");
			if (feature != null && feature.equalsIgnoreCase("title")) {
				return TITLE_NODE;
			}
		} else if (node instanceof Div) {
			Div head = (Div) node;
			String feature = head.getAttribute("class");
			if (feature != null && feature.equalsIgnoreCase("sub-title")) {
				return SUB_TITLE_NODE;
			} else if (feature != null && feature.equalsIgnoreCase("body")) {
				return BODY_NODE;
			} else if (feature != null && feature.equalsIgnoreCase("thumbnail ")) {
				return IMAGE_NODE;
			}
		}
		return -1;
	}

	// public static void main(String[] args) {
	// NewsHeadlineParser nhp = new NewsHeadlineParser();
	// nhp.getNewsHeadlines("three in one", "TW");
	// }
}
